package com.shuda.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shuda.common.dto.PageDTO;
import com.shuda.common.dto.PageResult;
import com.shuda.common.exception.BusinessException;
import com.shuda.common.utils.SecurityUtils;
import com.shuda.system.dto.MenuDTO;
import com.shuda.system.dto.MenuQueryDTO;
import com.shuda.system.entity.MenuEntity;
import com.shuda.system.entity.RoleMenuEntity;
import com.shuda.system.entity.UserRoleEntity;
import com.shuda.system.mapper.MenuMapper;
import com.shuda.system.mapper.RoleMenuMapper;
import com.shuda.system.mapper.UserRoleMapper;
import com.shuda.system.service.MenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单服务实现类
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuEntity> implements MenuService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Override
    public PageResult<MenuDTO> getMenuPage(PageDTO pageDTO, MenuQueryDTO queryDTO) {
        Page<MenuEntity> page = new Page<>(pageDTO.getPageNum(), pageDTO.getPageSize());
        
        LambdaQueryWrapper<MenuEntity> wrapper = new LambdaQueryWrapper<>();
        
        if (StringUtils.hasText(queryDTO.getMenuName())) {
            wrapper.like(MenuEntity::getMenuName, queryDTO.getMenuName());
        }
        
        if (StringUtils.hasText(queryDTO.getMenuCode())) {
            wrapper.like(MenuEntity::getMenuCode, queryDTO.getMenuCode());
        }
        
        if (queryDTO.getMenuType() != null) {
            wrapper.eq(MenuEntity::getMenuType, queryDTO.getMenuType());
        }
        
        if (queryDTO.getStatus() != null) {
            wrapper.eq(MenuEntity::getStatus, queryDTO.getStatus());
        }
        
        if (StringUtils.hasText(queryDTO.getStartTime())) {
            wrapper.ge(MenuEntity::getCreateTime, queryDTO.getStartTime());
        }
        
        if (StringUtils.hasText(queryDTO.getEndTime())) {
            wrapper.le(MenuEntity::getCreateTime, queryDTO.getEndTime());
        }
        
        wrapper.orderByAsc(MenuEntity::getSort);
        
        IPage<MenuEntity> result = menuMapper.selectPage(page, wrapper);
        
        List<MenuDTO> dtoList = result.getRecords().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        
        return new PageResult<>(dtoList, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public MenuDTO getMenuById(Long id) {
        MenuEntity entity = menuMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException("菜单不存在");
        }
        return convertToDTO(entity);
    }

    @Override
    @Transactional
    public Long createMenu(MenuDTO menuDTO) {
        MenuEntity entity = convertToEntity(menuDTO);
        entity.setStatus(1); // 默认启用
        entity.setCreateBy(SecurityUtils.getCurrentUsername());
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateBy(SecurityUtils.getCurrentUsername());
        entity.setUpdateTime(LocalDateTime.now());
        entity.setDeleted(0);
        
        menuMapper.insert(entity);
        return entity.getId();
    }

    @Override
    @Transactional
    public void updateMenu(Long id, MenuDTO menuDTO) {
        MenuEntity existingEntity = menuMapper.selectById(id);
        if (existingEntity == null) {
            throw new BusinessException("菜单不存在");
        }
        
        MenuEntity entity = convertToEntity(menuDTO);
        entity.setId(id);
        entity.setUpdateBy(SecurityUtils.getCurrentUsername());
        entity.setUpdateTime(LocalDateTime.now());
        
        menuMapper.updateById(entity);
    }

    @Override
    @Transactional
    public void deleteMenu(Long id) {
        MenuEntity entity = menuMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException("菜单不存在");
        }
        
        // 检查是否有子菜单
        LambdaQueryWrapper<MenuEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MenuEntity::getParentId, id)
                .eq(MenuEntity::getDeleted, 0);
        
        if (menuMapper.selectCount(wrapper) > 0) {
            throw new BusinessException("该菜单存在子菜单，不能删除");
        }
        
        // 删除角色菜单关联
        LambdaQueryWrapper<RoleMenuEntity> roleMenuWrapper = new LambdaQueryWrapper<>();
        roleMenuWrapper.eq(RoleMenuEntity::getMenuId, id);
        roleMenuMapper.delete(roleMenuWrapper);
        
        // 逻辑删除菜单
        entity.setDeleted(1);
        entity.setUpdateBy(SecurityUtils.getCurrentUsername());
        entity.setUpdateTime(LocalDateTime.now());
        menuMapper.updateById(entity);
    }

    @Override
    @Transactional
    public void batchDeleteMenu(List<Long> ids) {
        if (ids != null && !ids.isEmpty()) {
            for (Long id : ids) {
                deleteMenu(id);
            }
        }
    }

    @Override
    @Transactional
    public void updateMenuStatus(Long id, Integer status) {
        MenuEntity entity = menuMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException("菜单不存在");
        }
        
        entity.setStatus(status);
        entity.setUpdateBy(SecurityUtils.getCurrentUsername());
        entity.setUpdateTime(LocalDateTime.now());
        menuMapper.updateById(entity);
    }

    @Override
    public List<MenuDTO> getAllEnabledMenus() {
        LambdaQueryWrapper<MenuEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MenuEntity::getStatus, 1)
                .eq(MenuEntity::getDeleted, 0)
                .orderByAsc(MenuEntity::getSort);
        
        List<MenuEntity> entities = menuMapper.selectList(wrapper);
        return entities.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<MenuDTO> getMenuTree() {
        List<MenuDTO> allMenus = getAllEnabledMenus();
        return buildMenuTree(allMenus, 0L);
    }

    @Override
    public List<MenuDTO> getUserMenus(Long userId) {
        // 获取用户角色
        LambdaQueryWrapper<UserRoleEntity> userRoleWrapper = new LambdaQueryWrapper<>();
        userRoleWrapper.eq(UserRoleEntity::getUserId, userId);
        
        List<UserRoleEntity> userRoleEntities = userRoleMapper.selectList(userRoleWrapper);
        List<Long> roleIds = userRoleEntities.stream()
                .map(UserRoleEntity::getRoleId)
                .collect(Collectors.toList());
        
        if (roleIds.isEmpty()) {
            return List.of();
        }
        
        // 获取角色菜单
        LambdaQueryWrapper<RoleMenuEntity> roleMenuWrapper = new LambdaQueryWrapper<>();
        roleMenuWrapper.in(RoleMenuEntity::getRoleId, roleIds);
        
        List<RoleMenuEntity> roleMenuEntities = roleMenuMapper.selectList(roleMenuWrapper);
        List<Long> menuIds = roleMenuEntities.stream()
                .map(RoleMenuEntity::getMenuId)
                .distinct()
                .collect(Collectors.toList());
        
        if (menuIds.isEmpty()) {
            return List.of();
        }
        
        // 获取菜单详情
        LambdaQueryWrapper<MenuEntity> menuWrapper = new LambdaQueryWrapper<>();
        menuWrapper.in(MenuEntity::getId, menuIds)
                .eq(MenuEntity::getStatus, 1)
                .eq(MenuEntity::getDeleted, 0)
                .orderByAsc(MenuEntity::getSort);
        
        List<MenuEntity> entities = menuMapper.selectList(menuWrapper);
        List<MenuDTO> menuDTOs = entities.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        
        return buildMenuTree(menuDTOs, 0L);
    }

    private List<MenuDTO> buildMenuTree(List<MenuDTO> menus, Long parentId) {
        return menus.stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .map(menu -> {
                    menu.setChildren(buildMenuTree(menus, menu.getId()));
                    return menu;
                })
                .collect(Collectors.toList());
    }

    private MenuDTO convertToDTO(MenuEntity entity) {
        MenuDTO dto = new MenuDTO();
        BeanUtils.copyProperties(entity, dto);
        return dto;
    }

    private MenuEntity convertToEntity(MenuDTO dto) {
        MenuEntity entity = new MenuEntity();
        BeanUtils.copyProperties(dto, entity);
        return entity;
    }
}